/**
 * 版权所有 2009-2015 中国中医科学院中医药信息研究所 何前锋 frontpeak@yahoo.com.cn
 **/
package cn.ac.cintcm.sh.domain;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import cn.ac.cintcm.prespring.util.Config;

/**
 *方剂
 */
public class Prescription extends Element {
    
    private static final String NEW_LINE = "\r\n";
    private static final String YAO_SPLITER = ",";
    private static final String LINK = "prHCAnalyzeOne.jsp?s=' + encodeURI(encodeURI('";

    public static DecimalFormat df = new DecimalFormat("0.#"); 
 
	private int id = -1;
    /**
     *方剂名称
     */
    private String name = "自拟方";
     
    /**
     *方剂中药组成原文
     */
    private String text;
     
    private Set<Herb> herbs;
	 
    private AbsentElement absent;
    /**
     * 一付服用次数
     */
    private int times = 3;
    private HashMap<String, Item> wei;
    private HashMap<String, Item> jing;
    private HashMap<String, Item> qi;
    private HashMap<String, Item> xiao;
	 

    public Prescription() {
        herbs = new HashSet<Herb>();
        absent = new AbsentElement();
    }

    /**
	 *获取方剂的组成中药
	 */
    public Set<Herb> getHerbs() {
        return herbs;
    }
    
    public void setHerbs(Set<Herb> herbs) {
        this.herbs = herbs;
    }
    
    public void setIsTransformed(boolean b) {
        Iterator<Herb> it = herbs.iterator();
        while (it.hasNext()) {
            Herb h = it.next();
            h.setTransformed(false);
        }
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }	 
    
    /**
     *@str:中药名称、剂量等组成的字符串
     *解析字符串，得到中药
     */
   public Prescription parseHerb(String herbstr) {
       Prescription p = null;
       if (herbstr != null) {
           String str = herbstr.trim().replaceAll("\n|\r\n|\r", "");
           
           if (str.length() > 0) {
               String[] hs = str.split(",|，");
               p = new Prescription();
               p.setText(str);
               p.setTimes(1);
               for (String s :hs) {
                   Herb h;
                   try {
                       h = new Herb(s);
                       HerbEntry he = Herbs.getHerb(h.getName());
                       if (he != null) {
                           h.setId(he.getId());
                           p.addHerb(h);
                       } else {
                           this.absent.addAbsentElement("中药", h.getName());
                       }
                   } catch (FormatException e) {
                       e.printStackTrace();
                   }
                }
           }
       }
       return p;
   }

   public void setTimes(int times) {
       this.times  = times;
       
   }

    public void analysis() {
        qi = this.getQiSummary();
        wei = this.getWeiSummary();
        jing = this.getJing();
        //this.getXiao();
    }

    public HashMap<String, Item> getJing() {
        if (herbs != null) {
            jing = new HashMap<String, Item>();
            for (Herb hs : herbs) {
                HerbEntry h = Herbs.getHerb(hs.getName());
                if (h != null ) {
                    if (hs.getUnit() != null) {
                        float strength = hs.getUnit().getQuantity() / h.getAvg();
                        List<String> nvs = h.getJing();
                        if (nvs != null) {
                            for (String nv : nvs) {
                                if (nv != null) {
                                    Item item = jing.get(nv);
                                    if (item != null) {
                                        item.addValue(strength);
                                    } else {
                                        item = new Item(nv, strength);
                                    }
                                    item.addHerb(hs);
                                    jing.put(nv, item);
                                }
                            }
                        }
                    }
                } else {
                    absent.addAbsentElement(AbsentElement.YAO, hs.getName());
                }
            }
        }
        return jing;
    }


    public HashMap<String, Item> getQi() {
        if (herbs != null) {
            qi = new HashMap<String, Item>();
            for (Herb hs : herbs) {
                HerbEntry h = Herbs.getHerb(hs.getName());
                if (h != null) {
                    if (hs.getUnit() != null) {
                        float strength = hs.getUnit().getQuantity() / h.getAvg();
                        String q = h.getQi();
                        if (q != null) {
                            Item item = qi.get(q);
                            if (item != null) {
                                item.addValue(strength);
                            } else {
                                item = new Item(q, strength);
                            }
                            item.addHerb(hs);
                            qi.put(q, item);
                        }
                    }
                } else {
                    absent.addAbsentElement(AbsentElement.YAO, hs.getName());
                }

            }
        }
        return qi;
    }
    
    public HashMap<String, Item> getQiSummary() {
        Set<String> visited = new HashSet<String>();
        HashMap<String, Item> qi = getQi();
        calQiSummary(qi, visited);
        return qi;
    }
    
    private void calQiSummary(HashMap<String, Item> qiItem, Set<String> visited) {
        boolean finished = true;
        String[] qis = qiItem.keySet().toArray(new String[qiItem.size()]);
        for (String qi : qis) {
            Item item = qiItem.get(qi);
            if (item != null && !visited.contains(item.getName())) {
                String name = Qi9.getParent(item.getName());
                if (name != null) {
                    if (!name.equals(Qi9.ROOT)) {
                        visited.add(item.getName());
                        finished = false;
                        float value = Qi9.getValue(item.getName()) * item.getValue();
                        Item ni = qiItem.get(name);
                        if (ni != null) {
                            ni.addValue(value);
                        } else {
                            ni = new Item(name, value);
                        }
                        ni.addHerbs(item.getPrescription());
                        qiItem.put(name, ni);
                    }
                } else {
                    absent.addAbsentElement(AbsentElement.QI, item.getName());
                }
            }
        }
        if (!finished) {
            calQiSummary(qiItem, visited);
        }
    }
    
    public HashMap<String, Item> getWeiSummary() {
        Set<String> visited = new HashSet<String>();
        HashMap<String, Item> wei = getWei();
        calWeiSummary(wei, visited);
        return wei;
    }
 
    
    private void calWeiSummary(HashMap<String, Item> qiItem, Set<String> visited) {
        boolean finished = true;
        String[] qis = qiItem.keySet().toArray(new String[qiItem.size()]);
        for (String q : qis) {
            Item item = qiItem.get(q);
            if (item != null && !visited.contains(item.getName())) {
                String name = Wei.getParent(item.getName());
                if (name != null) {
                    if (!name.equals(Wei.ROOT)) {
                        visited.add(item.getName());
                        finished = false;
                        float value = Wei.getValue(item.getName()) * item.getValue();
                        Item ni = qiItem.get(name);
                        if (ni != null) {
                            ni.addValue(value);
                        } else {
                            ni = new Item(name, value);
                        }
                        ni.addHerbs(item.getPrescription());
                        qiItem.put(name, ni);
                    }
                } else {
                    absent.addAbsentElement(AbsentElement.WEI, item.getName());
                }
            }
        }
        if (!finished) {
            calWeiSummary(qiItem, visited);
        }
    }
    
    public HashMap<String, Item> getWei() {
        if (herbs != null) {
            wei = new HashMap<String, Item>();
            for (Herb hs : herbs) {
                HerbEntry h = Herbs.getHerb(hs.getName());
                if (h != null) {
                    if (hs.getUnit() != null) {
                        float strength = hs.getUnit().getQuantity() / h.getAvg();
                        List<String> ws = h.getWei();
                        if (ws != null) {
                            for (String w: ws) {
                                Item item = wei.get(w);
                                if (item != null) {
                                    item.addValue(strength);
                                } else {
                                    item = new Item(w, strength);
                                }
                                item.addHerb(hs);
                                wei.put(w, item);
                            }
                        }
                    }
                } else {
                    absent.addAbsentElement(AbsentElement.YAO, hs.getName());
                }

            }
        }
        return wei;
    }

    public HashMap<String, Item> getXiao() {
        if (herbs != null) {
            xiao = new HashMap<String, Item>();
            for (Herb hs : herbs) {
                HerbEntry h = Herbs.getHerb(hs.getName());
                if (h != null) {
                    if (hs.getUnit() != null) {
                        float strength = hs.getUnit().getQuantity() / h.getAvg();
                        List<String> nvs = h.getXiao();
                        if (nvs != null) {
                            for (String nv : nvs) {
                                if (nv != null) {
                                    Item item = xiao.get(nv);
                                    if (item != null) {
                                        item.addValue(strength);
                                    } else {
                                        item = new Item(nv, strength);
                                    }
                                    item.addHerb(hs);
                                    xiao.put(nv, item);
                                }
                            }
                        }
                    }
                } else {
                    absent.addAbsentElement(AbsentElement.YAO, hs.getName());
                }

            }
        }
        return xiao;
    }

    public void addHerb(Herb herb) {
        herbs.add(herb);
    }


    public void addHerbs(Prescription p) {
        if (p != null) {
            herbs.addAll(p.getHerbs());
        }
        
    }


    public String getName() {
        return name;
    }


    public void setName(String name) {
        this.name = name;
    }
    
    public String toString() {
        StringBuilder str = new StringBuilder();
        if (herbs != null) {
            for (Herb nv : herbs) {
                str.append(nv.getName());
                str.append(df.format(nv.getUnit().getQuantity()));
                str.append(nv.getUnit().getUnit());
            }
        }
        return str.toString();
    }
    
    public String toElements() {
        StringBuilder str = new StringBuilder();
        if (herbs!= null) {
            for (Herb nv : herbs) {
                str.append(nv);
                str.append(YAO_SPLITER);
            }
            if (str.length() > 0) {
                str.deleteCharAt(str.length() - 1);
            }
        }
        return str.toString();       
    }
    
    public String printTree() {
        StringBuilder sb = new StringBuilder();
        sb.append("d.add(0,-1,'");
        sb.append(this.name);
        sb.append("');");
        sb.append(NEW_LINE);
        
        sb.append("d.add(1,0,'气");
        sb.append(df.format(qi.get("气").getValue()));
        sb.append("');");
        sb.append(NEW_LINE);
        
        id = 2;
        sb.append(printQiTree("气", 1));
        
        sb.append("d.add(");
        sb.append(id);
        sb.append(",0,'味");
        sb.append("');");
        sb.append(NEW_LINE);
        sb.append(printWeiTree("味", id++));
        
        sb.append("d.add(");
        sb.append(id);
        sb.append(",0,'归经");
        sb.append("');");
        sb.append(NEW_LINE);
        sb.append(printHash(jing, id++));
        
        /*sb.append("d.add(");
        sb.append(id);
        sb.append(",0,'功效");
        sb.append("');");
        sb.append(NEW_LINE);
        sb.append(printHash(xiao, id++));        
        */
        return sb.toString();
    }

    private String printHash(HashMap<String, Item> hm, int parent) {
        StringBuilder sb = new StringBuilder();
        if (hm != null) {
            Item[] items = hm.values().toArray(new Item[hm.size()]);
            Arrays.sort(items);
            for(Item it : items) {
                String link = LINK +  it.getPrescription().toElements();
                sb.append("d.add(");
                sb.append(id++);
                sb.append(",");
                sb.append(parent);
                sb.append(",'");
                sb.append(it.getName());
                sb.append(df.format(it.getValue()));
                sb.append("  -----");
                sb.append(it.getPrescription());
                sb.append("','");
                sb.append(link);
                sb.append("')),'");
                sb.append(it.getPrescription());
                sb.append("','');");
                sb.append(NEW_LINE);
            }
        }
        return sb.toString();
    }

    private String printWeiTree(String root, int parent) {
        StringBuilder sb = new StringBuilder();
        List<String> childrenList = Wei.getChildren(root);
        List<String> children = sortWei(childrenList);
        if (children.size() > 0) {
            for (String c : children) {
                if (wei.get(c) != null) {
                    String link = LINK+ wei.get(c).getPrescription().toElements();
                    sb.append("d.add(");
                    sb.append(id);
                    sb.append(",");
                    sb.append(parent);
                    sb.append(",'");
                    sb.append(c);
                    sb.append(df.format(wei.get(c).getValue()));
                    sb.append("  -----");
                    sb.append(wei.get(c).getPrescription());
                    sb.append("','");
                    sb.append(link);
                    sb.append("')),'");
                    sb.append(wei.get(c).getPrescription());
                    sb.append("','');");
                    sb.append(NEW_LINE);
                    sb.append(printWeiTree(c, id++));
                }
            }
        }
        return sb.toString();
    }

    private List<String> sortWei(List<String> children) {
        float[] values = new float[children.size()];
        List<String> list = new ArrayList<String>();
        HashMap<Float, String> ws = new HashMap<Float, String>();
        int i = 0;
        for (String c : children) {
            if (wei.get(c) != null) {
                values[i] = wei.get(c).getValue();
                ws.put(values[i], c);
                i++;
            }
        }
        Arrays.sort(values);
        for (int j = children.size() - 1; j >= children.size() - i; j--) {
            float value = values[j];
            list.add(ws.get(value));
        }
        return list;
    }

    private String printQiTree(String root, int parent) {
        StringBuilder sb = new StringBuilder();
        List<String> children = Qi9.getChildren(root);
        if (children.size() > 0) {
            for (String c : children) {
                if (qi.get(c) != null) {
                    String link = LINK + qi.get(c).getPrescription().toElements();
                    sb.append("d.add(");
                    sb.append(id);
                    sb.append(",");
                    sb.append(parent);
                    sb.append(",'");
                    sb.append(c);
                    sb.append(df.format(qi.get(c).getValue()));
                    sb.append("  -----");
                    sb.append(qi.get(c).getPrescription());
                    sb.append("','");
                    sb.append(link);
                    sb.append("')),'");
                    sb.append(qi.get(c).getPrescription());
                    sb.append("','');");
                    sb.append(NEW_LINE);
                    sb.append(printQiTree(c, id++));
                }
            }
        }
        return sb.toString();
    }

    public AbsentElement getAbsent() {
        return absent;
    }
    
    public String getHtml(boolean original, String title) {
        StringBuffer sb = new StringBuffer();
        sb.append("<tr>");
        sb.append("<td colspan=4>");
        sb.append(title );
        sb.append("</td>");
        sb.append("</tr>");
        sb.append("<tr>");
        sb.append("<td>");
        sb.append("药名");
        sb.append("</td>");
        sb.append("<td>");
        sb.append("剂量");
        sb.append("</td>");
        sb.append("<td>");
        sb.append("单位");
        sb.append("</td>");
        sb.append("<td>");
        sb.append("备注");
        sb.append("</td>");
        sb.append("</tr>");
        Iterator<Herb> it = herbs.iterator();
        while (it.hasNext()) {
            sb.append("<tr>");
            sb.append(it.next().getHtml(original));
            sb.append("</tr>");
        }
        return sb.toString();
    }

    public void setConversion(Conversion c) {
        if (c != null) {
            HashMap<Integer, Unit> units = c.getHerbsUnit();
            if (herbs != null) {
                for (Herb h : herbs) {
                    h.setUnit(units.get(h.getId()));
                }
            }
        }
        
    }

    public String getCompositStr() {
        StringBuffer sb = new StringBuffer();
        sb.append(getId());
        sb.append(Config.FIELD_SPLITTER);
        for (Herb h : getHerbs()) {
            sb.append(h.getId());
            sb.append(Config.ITEM_SPLITTER);
        }
        sb.deleteCharAt(sb.length() - 1);
        return sb.toString();
        
    }

    public HashMap<Integer, Unit> getComposition() {
        HashMap<Integer, Unit> units = null;
       if (herbs != null) {
           units = new HashMap<Integer, Unit>();
           for (Herb h : herbs) {
               units.put(h.getId(), h.getUnit());
           }
       }
        return units;
    }


}